﻿using System;
using System.Data;
using System.Data.OleDb;
using System.Drawing.Printing;
using System.Reflection;
using C1.Win.C1Preview;
using C1.C1Report;
using PCSUtils.Framework.ReportFrame;
using PCSUtils.Utils;
using C1PrintPreviewDialog = PCSUtils.Framework.ReportFrame.C1PrintPreviewDialog;

namespace BaoCaoDuTruItem
{
	[Serializable]
	public class BaoCaoDuTruItem : MarshalByRefObject, IDynamicReport
	{
		public BaoCaoDuTruItem()
		{
		}

		private string mConnectionString;
		private ReportBuilder mReportBuilder;
		private C1PrintPreviewControl mReportViewer;
		private object mResult;

		/// <summary>
		/// ConnectionString, provide for the Dynamic Report
		/// ALlow Dynamic Report to access the DataBase of PCS
		/// </summary>
		public string PCSConnectionString
		{
			get { return mConnectionString; }
			set { mConnectionString = value; }
		}

		/// <summary>
		/// Report Builder Utility Object
		/// Dynamic Report can use this object to render, modify, layout the report
		/// </summary>
		public ReportBuilder PCSReportBuilder
		{
			get { return mReportBuilder; }
			set { mReportBuilder = value; }
		}

		/// <summary>
		/// ReportViewer Object, provide for the DynamicReport, 
		/// allow Dynamic Report to manipulate with the REportViewer, 
		/// modify the report after rendered if needed
		/// </summary>
		public C1PrintPreviewControl PCSReportViewer
		{
			get { return mReportViewer; }
			set { mReportViewer = value; }
		}

		/// <summary>
		/// Store other result if any. Ussually we store return DataTable here to display on the ReportViewer Form's Grid
		/// </summary>
		public object Result
		{
			get { return mResult; }
			set { mResult = value; }
		}

		private bool mUseReportViewerRenderEngine = false;

		/// <summary>
		/// Notify PCS whether the rendering report process is run by
		/// this IDynamicReport or the ReportViewer Engine (in the ReportViewer form)
		/// </summary>
		public bool UseReportViewerRenderEngine
		{
			get { return mUseReportViewerRenderEngine; }
			set { mUseReportViewerRenderEngine = value; }
		}

		private string mReportFolder = string.Empty;
		/// <summary>
		/// Inform External Process where to find out the ReportLayout	 ( the PCS' ReportDefinition Folder Path )
		/// </summary>				
		public string ReportDefinitionFolder
		{
			get { return mReportFolder; }
			set { mReportFolder = value; }
		}


		private string mLayoutFile = string.Empty;		
		/// <summary>
		/// Inform External Process about the Layout file
		/// in which PCS instruct to use
		/// (PCS will assign this property while ReportViewer Form execute,
		/// ReportVIewer form will use the layout file in the report config entry to put in this property)
		/// </summary>		
		public string ReportLayoutFile
		{
			get 
			{
				return mLayoutFile;
			}
			set
			{
				mLayoutFile = value;
			}
		}


		public object Invoke(string pstrMethod, object[] pobjParameters)
		{
			return this.GetType().InvokeMember(pstrMethod, BindingFlags.InvokeMethod, null, this, pobjParameters);
		}

		public DataTable ExecuteReport(string pstrProductID, string pstrProductionLineID, string pstrFullname)
		{
			DataTable dtbData = GetReportData(pstrProductID);
			DataTable dtbReportData = dtbData.Clone();
			string strFilter = "(Revision = 'CTTC' OR MakeItem = 0)";
			if (pstrProductionLineID != null && pstrProductionLineID != string.Empty)
				strFilter += " AND ProductionLineID = " + pstrProductionLineID;
			DataRow[] drowNoneMake = dtbData.Select(strFilter);
			foreach (DataRow drowNone in drowNoneMake)
				dtbReportData.Rows.Add(drowNone.ItemArray);

			if (dtbData.Rows.Count > 0)
			{
				dtbReportData.Columns["FGoodsCode"].DefaultValue = dtbData.Rows[0]["FGoodsCode"];
				dtbReportData.Columns["SPartNo"].DefaultValue = dtbData.Rows[0]["SPartNo"];
				dtbReportData.Columns["WOQuantity"].DefaultValue = dtbData.Rows[0]["WOQuantity"];
				dtbReportData.Columns["ServerDate"].DefaultValue = dtbData.Rows[0]["ServerDate"];
			}
			else
			{
				DataRow drowInfo = GetProductInfo(pstrProductID);
				dtbReportData.Columns["FGoodsCode"].DefaultValue = drowInfo["FGoodsCode"];
				dtbReportData.Columns["SPartNo"].DefaultValue = drowInfo["SPartNo"];
				dtbReportData.Columns["WOQuantity"].DefaultValue = drowInfo["WOQuantity"];
				dtbReportData.Columns["ServerDate"].DefaultValue = drowInfo["ServerDate"];
			}
			DataTable dtbBOM = ListBom();

			DataRow[] drowsBOM = dtbBOM.Select("ProductID = " + pstrProductID + " AND MakeItem = 1 AND Revision <> 'CTTC'");
			foreach (DataRow drowData in drowsBOM)
				AddData(drowData, dtbReportData, dtbBOM, pstrProductionLineID);

			#region report

			C1Report rptReport = new C1Report();
			
			if (mLayoutFile == string.Empty)
				mLayoutFile = "BaoCaoDuTru.xml";
			rptReport.Load(mReportFolder + "\\" + mLayoutFile, rptReport.GetReportInfo(mReportFolder + "\\" + mLayoutFile)[0]);
			rptReport.Layout.PaperSize = PaperKind.A4;
					
			#region report parameter
			string strLineCode = string.Empty;

			if (pstrProductionLineID != null && pstrProductionLineID.Length > 0)
				strLineCode = GetProductionLineInfo(pstrProductionLineID);
			try
			{
				rptReport.Fields["fldProductionLine"].Text = strLineCode;
			}
			catch{}
			try
			{
				rptReport.Fields["fldFullname"].Text = pstrFullname;
			}
			catch{}
				
			#endregion
				
			// set datasource object that provides data to report.
			rptReport.DataSource.Recordset = null;
			rptReport.DataSource.Recordset = dtbReportData;
			// render report
			rptReport.Render();

			// render the report into the PrintPreviewControl
			C1PrintPreviewDialog ppvViewer = new C1PrintPreviewDialog();
			ppvViewer.FormTitle = rptReport.Fields["fldTitle"].Text;
			ppvViewer.ReportViewer.NavigationPanelVisible = false;
			ppvViewer.ReportViewer.Document = rptReport.Document;
			ppvViewer.Show();
			#endregion

			return dtbReportData;
		}

		private void AddData(DataRow pdrowData, DataTable pdtbReportData, DataTable pdtbBOM, string pstrProductionLineID)
		{
			string strProductID = pdrowData["ComponentID"].ToString();
			string strRevision = pdrowData["Revision"].ToString();
			bool blnMakeItem = Convert.ToBoolean(pdrowData["MakeItem"]);
			decimal decRequiredQty = Convert.ToDecimal(pdrowData["Quantity"]);
			if (pstrProductionLineID != null && pstrProductionLineID != string.Empty)
				if (!pdrowData["ProductionLineID"].ToString().Equals(pstrProductionLineID))
					goto Next;
			if (!blnMakeItem || strRevision == "CTTC")
			{
				string strComID = pdrowData["ComponentID"].ToString();
				DataRow[] drowExist = pdtbReportData.Select("ProductID = " + strComID);
				if (drowExist.Length > 0)
				{
					decimal decBomQty = Convert.ToDecimal(drowExist[0]["BomQty"]);
					decimal decParentQty = Convert.ToDecimal(pdrowData["BomQty"]);
					decimal decRate = Convert.ToDecimal(pdrowData["Rate"]);
					decBomQty += decParentQty * Convert.ToDecimal(pdrowData["Quantity"]);
					drowExist[0]["BomQty"] = decBomQty;
					if (decRate != 0)
						drowExist[0]["Weight"] = decBomQty * decRate;
				}
				else
				{
					decimal decParentQty = Convert.ToDecimal(pdrowData["BomQty"]);
					decimal decBomQty = decParentQty * Convert.ToDecimal(pdrowData["Quantity"]);
					decimal decRate = Convert.ToDecimal(pdrowData["Rate"]);
					DataRow drowNew = pdtbReportData.NewRow();
					drowNew["PartNo"] = pdrowData["Code"];
					drowNew["ProductID"] = pdrowData["ComponentID"];
					drowNew["PartName"] = pdrowData["Description"];
					drowNew["BomQty"] = decBomQty;
					drowNew["UM"] = pdrowData["UM"];
					drowNew["ProductionLineID"] = pdrowData["ProductionLineID"];
					if (decRate != 0)
						drowNew["Weight"] = decBomQty * decRate;
					pdtbReportData.Rows.Add(drowNew);
				}
			}
			Next:
			if (strRevision != "CTTC")
			{
				DataRow[] drowComs = pdtbBOM.Select("ProductID = " + strProductID);
				foreach (DataRow drowCom in drowComs)
				{
					decimal decComQty = Convert.ToDecimal(drowCom["Quantity"]);
					drowCom["Quantity"] = decComQty * decRequiredQty;
					AddData(drowCom, pdtbReportData, pdtbBOM, pstrProductionLineID);
				}
			}
		}

		private DataRow GetProductInfo(string pstrProductID)
		{
			OleDbConnection cn = null;
			try
			{
				cn = new OleDbConnection(mConnectionString);
				DataTable dtbItem = new DataTable();
				string strSql = "SELECT '' FGoodsCode, P.Code + ' (' + P.Description + ')' SPartNo, 1 WOQuantity, getdate() ServerDate"
					+ " FROM ITM_Product P "
					+ " WHERE P.ProductID = " + pstrProductID;
				OleDbDataAdapter odad = new OleDbDataAdapter(strSql, cn);
				odad.Fill(dtbItem);
				return dtbItem.Rows[0];
			}
			finally
			{
				if (cn != null)
					if (cn.State != ConnectionState.Closed)
						cn.Close();
			}
		}

		private DataTable GetReportData(string pstrProductID)
		{
			OleDbConnection cn = null;
			try
			{
				cn = new OleDbConnection(mConnectionString);
				DataTable dtbItem = new DataTable();
				string strSql = "SELECT '' FGoodsCode, P.Code + ' (' + P.Description + ')' SPartNo, 1 WOQuantity, C.ProductID,"
					+ " C.Code PartNo, C.Description PartName, B.Quantity BomQty, UM.Code UM, 1 Quantity, C.Revision, ISNULL(C.MakeItem,0) MakeItem,"
					+ " B.Quantity * ISNULL(C.Rate,0) Weight, ISNULL(P.ProductionLineID,0) ProductionLineID, getdate() ServerDate"
					+ " FROM ITM_Product P JOIN ITM_BOM B ON P.ProductID = B.ProductID"
					+ " JOIN ITM_Product C ON B.ComponentID = C.ProductID"
					+ " JOIN MST_UnitOfMeasure UM ON UM.UnitOfMeasureID = B.BomUMID"
					+ " WHERE P.ProductID = " + pstrProductID;
				OleDbDataAdapter odad = new OleDbDataAdapter(strSql, cn);
				odad.Fill(dtbItem);
				return dtbItem;
			}
			finally
			{
				if (cn != null)
					if (cn.State != ConnectionState.Closed)
						cn.Close();
			}
		}
		private DataTable ListBom()
		{
			OleDbConnection cn = null;
			try
			{
				cn = new OleDbConnection(mConnectionString);
				DataTable dtbItem = new DataTable();
				string strSql = "SELECT '' FGoodsCode, '' SPartNo, 1 WOQuantity, B.ProductID,"
					+ " ComponentID, 1 BomQty, B.Quantity, ISNULL(P.Rate,0) Rate, 0 Weight, getdate() ServerDate,"
					+ " P.Code, P.Description, P.Revision, ISNULL(P.MakeItem,0) MakeItem, UM.Code UM,"
					+ " ISNULL(C.ProductionLineID,0) ProductionLineID"
					+ " FROM ITM_BOM B JOIN ITM_Product P ON B.ComponentID = P.ProductID"
					+ " JOIN ITM_Product C ON B.ProductID = C.ProductID"
					+ " JOIN MST_UnitOfMeasure UM ON UM.UnitOfMeasureID = B.BomUMID";
				OleDbDataAdapter odad = new OleDbDataAdapter(strSql, cn);
				odad.Fill(dtbItem);
				return dtbItem;
			}
			finally
			{
				if (cn != null)
					if (cn.State != ConnectionState.Closed)
						cn.Close();
			}
		}

		private string GetProductionLineInfo(string pstrProductionLineID)
		{
			OleDbConnection cn = null;
			try
			{
				cn = new OleDbConnection(mConnectionString);
				string strSql = "SELECT Code + ' (' + Name + ')' FROM PRO_ProductionLine"
					+ " WHERE ProductionLineID = " + pstrProductionLineID;
				OleDbCommand ocmd = new OleDbCommand(strSql, cn);
				ocmd.Connection.Open();
				return ocmd.ExecuteScalar().ToString();
			}
			finally
			{
				if (cn != null)
					if (cn.State != ConnectionState.Closed)
						cn.Close();
			}
		}
	}
}